package com.markby.fscm.cryptogram.domain.standard0016;


import com.markby.fscm.cryptogram.uitls.HexUtils;
import lombok.Data;

import java.nio.ByteOrder;

import static com.markby.fscm.cryptogram.domain.standard0016.Constant0016.ECC_MAX_XCOORDINATE_BITS_LEN;
import static com.markby.fscm.cryptogram.domain.standard0016.Constant0016.ECC_MAX_YCOORDINATE_BITS_LEN;
import static com.markby.fscm.cryptogram.uitls.HexUtils.intToBytes;


/**
 * 0016-2023规范 ECC密文数据结构
 * ULONG 为32位无符号整数
 * typedef struct Struct_ECCCIPHERBLOB(
 * BYTE 	XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN/8];	// 与y组成椭圆曲线上的点(x,y)
 * BYTE 	YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN/8];	// 与x组成椭圆曲线上的点(x,y)
 * BYTE 	HASH[32];										// 明文的杂凑值
 * ULONG 	CipherLen;										// 密文数据长度
 * BYTE 	Cipher[1];										// 密文数据(实际长度为CipherLen)
 * }ECCCIPHERBLOB，*PECCCIPHERBLOB;
 */
@Data
public class ECCCIPHERBLOB {
    private byte[] XCoordinate;
    private byte[] YCoordinate;
    private byte[] Hash;
    private int CipherLen;
    private byte[] Cipher;

    public ECCCIPHERBLOB(byte[] xCoordinate, byte[] yCoordinate, byte[] hash, int cipherLen, byte[] cipher) {
        if (xCoordinate.length != ECC_MAX_XCOORDINATE_BITS_LEN / 8) {
            throw new IllegalArgumentException("Invalid XCoordinate length: " + xCoordinate.length);
        }
        if (yCoordinate.length != ECC_MAX_YCOORDINATE_BITS_LEN / 8) {
            throw new IllegalArgumentException("Invalid YCoordinate length: " + yCoordinate.length);
        }
        if (hash.length != 32) {
            throw new IllegalArgumentException("Invalid Hash length: " + hash.length);
        }
        if (cipher.length != cipherLen) {
            throw new IllegalArgumentException("Invalid Cipher length: " + cipher.length);
        }
        this.XCoordinate = xCoordinate;
        this.YCoordinate = yCoordinate;
        this.Hash = hash;
        this.CipherLen = cipherLen;
        this.Cipher = cipher;
    }

    public ECCCIPHERBLOB(byte[] randomNumEncryptWithSM2, int BitLen) {
        if (randomNumEncryptWithSM2.length != 113) {
            throw new IllegalArgumentException("ECCCIPHERBLOB length must be 113");
        }
        System.out.println("对称密钥密文长度:" + randomNumEncryptWithSM2.length);
        System.out.println("对称密钥密文:" + HexUtils.hexify_haveSpace(randomNumEncryptWithSM2));
        if (BitLen == 256) {
            int len = ECC_MAX_XCOORDINATE_BITS_LEN / 8 / 2;
            byte[] x = new byte[32];//x分量
            byte[] y = new byte[32];//y分量
            byte[] m = new byte[32];//杂凑值
            byte[] c = new byte[16];//密文
            System.arraycopy(randomNumEncryptWithSM2, 1, x, 0, len);
            System.arraycopy(randomNumEncryptWithSM2, 33, y, 0, len);
            System.arraycopy(randomNumEncryptWithSM2, 65, m, 0, 32);
            System.arraycopy(randomNumEncryptWithSM2, 97, c, 0, 16);

            this.XCoordinate = new byte[64];
            this.YCoordinate = new byte[64];
            System.arraycopy(x, 0, XCoordinate, XCoordinate.length - len, len);
            System.arraycopy(y, 0, YCoordinate, YCoordinate.length - len, len);
            this.Hash = m;
            this.CipherLen = c.length;
            this.Cipher = c;
        } else {
            throw new IllegalArgumentException("ECCCIPHERBLOB NOT SUPPORT BitLen 512 FOR NOW!");
        }


    }

    public byte[] getBytes() {
        byte[] xCoordinateBytes = XCoordinate;
        byte[] yCoordinateBytes = YCoordinate;
        byte[] hashBytes = Hash;
        byte[] cipherLenBytes = intToBytes(CipherLen, ByteOrder.LITTLE_ENDIAN);
        byte[] cipherBytes = Cipher;
        byte[] result = new byte[xCoordinateBytes.length + yCoordinateBytes.length + hashBytes.length + cipherLenBytes.length + cipherBytes.length];
        System.arraycopy(xCoordinateBytes, 0, result, 0, xCoordinateBytes.length);
        System.arraycopy(yCoordinateBytes, 0, result, xCoordinateBytes.length, yCoordinateBytes.length);
        System.arraycopy(hashBytes, 0, result, xCoordinateBytes.length + yCoordinateBytes.length, hashBytes.length);
        System.arraycopy(cipherLenBytes, 0, result, xCoordinateBytes.length + yCoordinateBytes.length + hashBytes.length, cipherLenBytes.length);
        System.arraycopy(cipherBytes, 0, result, xCoordinateBytes.length + yCoordinateBytes.length + hashBytes.length + cipherLenBytes.length, cipherBytes.length);
        return result;
    }
}
